<template>
  <div class="code-editor-container">
    <div class="editor-header">
      <el-select v-model="language" size="small" @change="handleLanguageChange" style="width: 50%;">
        <el-option v-for="lang in languageOptions" :key="lang.value" :label="lang.label" :value="lang.value" />
      </el-select>
      <el-button @click="copyCode" size="small">
        <el-icon>
          <DocumentCopy />
        </el-icon>
        复制
      </el-button>
      <div class="status-indicator">
        {{ statusText }}
      </div>
    </div>

    <div ref="editorContainer" @mouseup.stop="handleClick" class="editor-wrapper"></div>

    <div v-if="errorMessage" class="error-message">
      {{ errorMessage }}
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, watch, nextTick } from 'vue'
import { DocumentCopy } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'

// CodeMirror 6 核心模块
import { EditorView, basicSetup } from 'codemirror'
import { EditorState } from '@codemirror/state'
import { javascript } from '@codemirror/lang-javascript'
import { html } from '@codemirror/lang-html'
import { css } from '@codemirror/lang-css'
import { json } from '@codemirror/lang-json'
import { python } from '@codemirror/lang-python'
import { java } from '@codemirror/lang-java'
import { sql } from '@codemirror/lang-sql'
import { oneDark } from '@codemirror/theme-one-dark'
import { keymap } from '@codemirror/view'
import { indentWithTab } from '@codemirror/commands'

// 定义组件属性
const props = defineProps({
  modelValue: {
    type: String,
    default: ''
  },
  language: {
    type: String,
    default: 'javascript'
  },
  height: {
    type: [Number, String],
    default: 400
  },
  readonly: {
    type: Boolean,
    default: false
  },
  placeholder: {
    type: String,
    default: '请输入代码...'
  }
})

const emit = defineEmits<{
  (e: 'update:modelValue', value: string): void
  (e: 'change', value: string): void
}>()

// 响应式数据
const editorContainer = ref<HTMLDivElement | null>(null)
const language = ref(props.language)
const errorMessage = ref('')
const statusText = ref('就绪')
let editor: EditorView | null = null

// 语言选项
const languageOptions = [
  { label: 'JavaScript', value: 'javascript' },
  { label: 'TypeScript', value: 'typescript' },
  { label: 'HTML', value: 'html' },
  { label: 'CSS', value: 'css' },
  { label: 'JSON', value: 'json' },
  { label: 'Python', value: 'python' },
  { label: 'Java', value: 'java' },
  { label: 'SQL', value: 'sql' }
]

// 根据语言获取对应的语言支持扩展
const getLanguageExtension = (lang: string) => {
  switch (lang) {
    case 'javascript':
      return javascript()
    case 'typescript':
      return javascript({ typescript: true })
    case 'html':
      return html()
    case 'css':
      return css()
    case 'json':
      return json()
    case 'python':
      return python()
    case 'java':
      return java()
    case 'sql':
      return sql()
    default:
      return javascript()
  }
}

// 监听modelValue变化
watch(() => props.modelValue, (newVal) => {
  if (editor && editor.state.doc.toString() !== newVal) {
    editor.dispatch({
      changes: {
        from: 0,
        to: editor.state.doc.length,
        insert: newVal || ''
      }
    })
  }
})

// 监听语言变化
watch(language, async (newLang) => {
  if (editor) {
    try {
      const currentValue = editor.state.doc.toString()
      editor.destroy()
      await nextTick()
      initEditor(currentValue, newLang)
      statusText.value = `语言: ${newLang}`
    } catch (error: any) {
      errorMessage.value = `切换语言失败: ${error.message}`
      console.error('切换语言错误:', error)
    }
  }
})

// 处理语言变化
const handleLanguageChange = (newLang: string) => {
  language.value = newLang
}

// 复制代码到剪贴板
const copyCode = async () => {
  if (!editor) return

  try {
    const code = editor.state.doc.toString()
    await navigator.clipboard.writeText(code)
    ElMessage.success('代码已复制到剪贴板')
  } catch (error) {
    ElMessage.error('复制失败')
    console.error('复制错误:', error)
  }
}

// 初始化编辑器
const initEditor = (initialValue?: string, lang?: string) => {
  if (!editorContainer.value) return

  try {
    const doc = initialValue !== undefined ? initialValue : props.modelValue || ''
    const language = lang || props.language

    // 创建编辑器状态 - 修复 keymap 的使用
    const state = EditorState.create({
      doc,
      extensions: [
        basicSetup,
        getLanguageExtension(language),
        oneDark,
        // 直接使用 keymap，而不是通过 of 方法
        keymap.of([indentWithTab]),
        EditorView.updateListener.of(update => {
          if (update.docChanged) {
            const value = update.state.doc.toString()
            emit('update:modelValue', value)
            emit('change', value)
            statusText.value = `字符数: ${value.length}`
          }
          if (update.selectionSet) {
            const selection = update.state.selection.main
            const line = update.state.doc.lineAt(selection.head)
            statusText.value = `行 ${line.number}, 列 ${selection.head - line.from + 1}`
          }
        }),
        EditorView.theme({
          '&': {
            fontSize: '14px'
          },
          '.cm-content': {
            caretColor: '#fff'
          },
          '.cm-cursor, .cm-dropCursor': {
            borderLeftColor: '#fff'
          },
          '&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-activeLineBackground': {
            backgroundColor: 'rgba(255, 255, 255, 0.1)'
          }
        })
      ]
    })

    // 创建编辑器视图
    editor = new EditorView({
      state,
      parent: editorContainer.value
    })

  } catch (error: any) {
    errorMessage.value = `编辑器初始化失败: ${error.message}`
    statusText.value = '错误'
    console.error('CodeMirror initialization error:', error)
  }
}

// 组件挂载后初始化编辑器
onMounted(() => {
  if (editorContainer.value) {
    // 设置容器高度
    const height = typeof props.height === 'number' ? `${props.height}px` : props.height
    editorContainer.value.style.height = height

    // 初始化编辑器
    initEditor()
  }
})

// 阻止事件冒泡
const handleClick = (event: any) => {
  event.stopPropagation()
}

// 组件卸载前销毁编辑器
onBeforeUnmount(() => {
  if (editor) {
    editor.destroy()
    editor = null
  }
})

// 暴露方法给父组件
defineExpose({
  copyCode
})
</script>

<style scoped>
.code-editor-container {
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  overflow: hidden;
}

.editor-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 12px;
  background-color: #f5f7fa;
  border-bottom: 1px solid #dcdfe6;
}

.status-indicator {
  font-size: 12px;
  color: #909399;
}

.editor-wrapper {
  min-height: 300px;
}

.error-message {
  padding: 8px 12px;
  background-color: #fef0f0;
  color: #f56c6c;
  font-size: 12px;
  border-top: 1px solid #fde2e2;
}

/* 确保 CodeMirror 编辑器占满容器 */
:deep(.cm-editor) {
  height: 100%;
  width: 100%;
}

:deep(.cm-scroller) {
  overflow: auto;
}

:deep(.cm-content) {
  padding: 12px;
}
</style>